package soccerscope.dialog;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import robocup.component.geometry.Vektor;
import soccerscope.model.Player;
import soccerscope.model.SoccerObject;
import soccerscope.training.ObjectTrainingModel;
import soccerscope.training.PlayerTrainingModel;
import soccerscope.training.ObjectTrainingModel.POSITION_TYPE;
import soccerscope.util.geom.Point2f;
import soccerscope.view.ObjectTrainingButton;

/**
 * This code was generated using CloudGarden's Jigloo SWT/Swing GUI Builder,
 * which is free for non-commercial use. If Jigloo is being used commercially
 * (ie, by a corporation, company or business for any purpose whatever) then you
 * should purchase a license for each developer using Jigloo. Please visit
 * www.cloudgarden.com for details. Use of Jigloo implies acceptance of these
 * licensing terms. ************************************* A COMMERCIAL LICENSE
 * HAS NOT BEEN PURCHASED for this machine, so Jigloo or this code cannot be
 * used legally for any corporate or commercial purpose.
 * *************************************
 */
public class ObjectTrainingPanel
    extends JPanel
    implements ActionListener, MouseListener, MouseMotionListener,
    ChangeListener, MouseWheelListener {

  private static final long    serialVersionUID = -4677894813944844081L;

  private ObjectTrainingButton objectTrainingButton;

  private JPanel               speedDir;

  private JPanel               other;

  private JCheckBox            active;

  private ButtonGroup          spdLengthGroup;

  private JSlider              maxSpeedSlide;

  private JRadioButton         maxSpeed;

  private JSlider              minSpeedSlide;

  private JRadioButton         minSpeed;

  private JSlider              sdirDiffSlide;

  private JLabel               slabel;

  private JSlider              diffSlide;

  private JLabel               alabel;

  private JLabel               hlabel;

  private JLabel               llabel;

  private JRadioButton         rectPosition;

  private ButtonGroup          positionButtons;

  private JSlider              heightSlide;

  private JSlider              lengthSlide;

  private JRadioButton         circPosition;

  private JRadioButton         fixedPosition;

  private JPanel               speedLen;

  private JPanel               angle;

  private JPanel               position;

  private JCheckBox            roundView;

  private JTabbedPane          EditTabPane;

  // object: player or ball + corresp. model
  private SoccerObject         object           = null;

  private ObjectTrainingModel  otm              = null;

  // factors for scaling
  private float                posFactor        = 0.5f;

  private float                mapFactor        = 0.2f;

  private JCheckBox            alignWithBody;

  /**
   * This dialog is called when a players training setup should be defined.
   * Therefore, the Player as well as the soccerscope instance should be given
   * as parameter. The Player contain a PlayerTrainingModel, which will be
   * altered using this dialog!
   * 
   * @param frame -
   *          the soccerscope-instance as main-frame
   * @param player -
   *          the corresponding player
   */
  public ObjectTrainingPanel() {

    super();
    this.initGUI();
  }

  /**
   * This method sets the SoccerObject, which is analyzed next. It may be either
   * a ball or a player. Depending on that, the gui shows different types of
   * adjustment possibilities.
   * 
   * @param so -
   *          the soccerobject
   */
  public void setObject(SoccerObject so,
      ObjectTrainingModel otm) {

    this.object = so;
    this.otm = otm;
    this.objectTrainingButton.setObject(so);
    // init the buttons and sliders:
    this.fixedPosition.setSelected(otm.getType() == POSITION_TYPE.FIXED);
    this.rectPosition.setSelected(otm.getType() == POSITION_TYPE.RECTANGULAR);
    this.circPosition.setSelected(otm.getType() == POSITION_TYPE.CIRCULAR);
    this.lengthSlide.setEnabled(otm.getType() != POSITION_TYPE.FIXED);
    this.lengthSlide.setValue((int) (otm.getY_pos_diff() / this.posFactor));
    this.heightSlide.setEnabled(otm.getType() != POSITION_TYPE.FIXED);
    this.heightSlide.setValue((int) (otm.getX_pos_diff() / this.posFactor));
    if (otm instanceof PlayerTrainingModel) {
      PlayerTrainingModel ptm = (PlayerTrainingModel) otm;
      this.diffSlide.setValue((int) ptm.getBody_angle_diff());
      this.alignWithBody.setSelected(ptm.getAlignSpeedWithBody());
      this.active.setSelected(ptm.isActive());
      this.roundView.setSelected(ptm.isRoundView());

      // reorder panels
      this.EditTabPane.removeAll();
      this.EditTabPane.addTab("Position", null, this.position, null);
      this.EditTabPane.addTab("BodyAngle", null, this.angle, null);
      this.EditTabPane.addTab("Speed-Direction", null, this.speedDir, null);
      this.EditTabPane.addTab("Speed-Length", null, this.speedLen, null);
      this.EditTabPane.addTab("Other", null, this.other, null);

    }
    else {
      this.EditTabPane.remove(this.angle);
      this.EditTabPane.remove(this.other);
      // angle.setEnabled(false);
      // other.setEnabled(false);
      // diffSlide.setValue((int)ptm.getBody_angle_diff());
      // alignWithBody.setSelected(ptm.getAlignSpeedWithBody());
      // active.setSelected(ptm.isActive());
      // roundView.setSelected(ptm.isRoundView());
    }
    this.sdirDiffSlide.setValue((int) otm.getSpeed_angle_diff());
    this.minSpeedSlide.setValue(otm.getMin_speed());
    this.maxSpeedSlide.setValue(otm.getMax_speed());
    this.objectTrainingButton.repaint();
  }

  private void initGUI() {

    try {
      {
        BorderLayout thisLayout = new BorderLayout();
        this.setLayout(thisLayout);
        {
          // buttongroups
          this.positionButtons = new ButtonGroup();
          this.spdLengthGroup = new ButtonGroup();
        }
        this.objectTrainingButton = new ObjectTrainingButton();
        this.add(this.objectTrainingButton, BorderLayout.NORTH);
        this.objectTrainingButton.addMouseListener(this);
        this.objectTrainingButton.addMouseWheelListener(this);
        this.objectTrainingButton.addMouseMotionListener(this);
      }
      {
        this.EditTabPane = new JTabbedPane();
        this.add(this.EditTabPane, BorderLayout.SOUTH);
        {
          this.position = new JPanel();
          GridLayout positionLayout = new GridLayout(7, 1);
          positionLayout.setRows(7);
          this.position.setLayout(positionLayout);
          this.EditTabPane.addTab("Position", null, this.position, null);
          {
            this.fixedPosition = new JRadioButton();
            this.position.add(this.fixedPosition);
            this.fixedPosition.setText("FIXED");
            this.positionButtons.add(this.fixedPosition);
            this.fixedPosition.addActionListener(this);
          }
          {
            this.rectPosition = new JRadioButton();
            this.position.add(this.rectPosition);
            this.rectPosition.setText("RECTANGLE");
            this.positionButtons.add(this.rectPosition);
            this.rectPosition.addActionListener(this);
          }
          {
            this.circPosition = new JRadioButton();
            this.position.add(this.circPosition);
            this.circPosition.setText("CIRCLE");
            this.positionButtons.add(this.circPosition);
            this.circPosition.addActionListener(this);
          }
          {
            this.llabel = new JLabel();
            this.position.add(this.llabel);
            this.llabel.setText("Length-Adjust:");
          }
          {
            this.lengthSlide = new JSlider();
            this.position.add(this.lengthSlide);
            this.lengthSlide.setValue(0);
            this.lengthSlide.setPaintTicks(true);
            this.lengthSlide.setMajorTickSpacing(10);
            this.lengthSlide.addChangeListener(this);
          }
          {
            this.hlabel = new JLabel();
            this.position.add(this.hlabel);
            this.hlabel.setText("Height-Adjust:");
          }
          {
            this.heightSlide = new JSlider();
            this.position.add(this.heightSlide);
            this.heightSlide.setValue(0);
            this.heightSlide.setMajorTickSpacing(10);
            this.heightSlide.setPaintTicks(true);
            this.heightSlide.addChangeListener(this);
          }
        }
        {
          this.angle = new JPanel();
          // FlowLayout angleLayout = new FlowLayout();
          // angleLayout.setAlignment(FlowLayout.LEFT);
          // angle.setLayout(angleLayout);
          GridLayout angleLayout = new GridLayout(7, 1);
          angleLayout.setRows(7);
          this.angle.setLayout(angleLayout);
          this.EditTabPane.addTab("BodyAngle", null, this.angle, null);
          {
            this.alabel = new JLabel();
            this.angle.add(this.alabel);
            this.alabel.setText("Adjust Diff:");
          }
          {
            this.diffSlide = new JSlider();
            this.angle.add(this.diffSlide);
            this.diffSlide.setValue(0);
            this.diffSlide.setMaximum(180);
            this.diffSlide.setPaintTicks(true);
            this.diffSlide.setPaintLabels(true);
            this.diffSlide.setMajorTickSpacing(30);
            this.diffSlide.addChangeListener(this);
          }
        }
        {
          this.speedDir = new JPanel();
          GridLayout spdirLayout = new GridLayout(7, 1);
          spdirLayout.setRows(7);
          this.speedDir.setLayout(spdirLayout);
          // FlowLayout speedDirLayout = new FlowLayout();
          // speedDirLayout.setAlignment(FlowLayout.LEFT);
          // speedDir.setLayout(speedDirLayout);
          this.EditTabPane.addTab("Speed-Direction", null, this.speedDir, null);
          {
            this.alignWithBody = new JCheckBox();
            this.speedDir.add(this.alignWithBody);
            this.alignWithBody.setText("Align Speed-Dir with Body-Dir");
            this.alignWithBody.addActionListener(this);
          }
          {
            this.slabel = new JLabel();
            this.speedDir.add(this.slabel);
            this.slabel.setText("Speed-Dir Diffusion:");
          }
          {
            this.sdirDiffSlide = new JSlider();
            this.speedDir.add(this.sdirDiffSlide);
            this.sdirDiffSlide.setMajorTickSpacing(30);
            this.sdirDiffSlide.setPaintTicks(true);
            this.sdirDiffSlide.setPaintLabels(true);
            this.sdirDiffSlide.setMaximum(180);
            this.sdirDiffSlide.addChangeListener(this);
          }
        }
        {
          this.speedLen = new JPanel();
          GridLayout splenLayout = new GridLayout(7, 1);
          splenLayout.setRows(7);
          this.speedLen.setLayout(splenLayout);
          // FlowLayout speedLenLayout = new FlowLayout();
          // speedLenLayout.setAlignment(FlowLayout.LEFT);
          // speedLen.setLayout(speedLenLayout);
          this.EditTabPane.addTab("Speed-Length", null, this.speedLen, null);
          this.speedLen.setPreferredSize(new Dimension(300, 300));
          {
            this.minSpeed = new JRadioButton();
            this.speedLen.add(this.minSpeed);
            this.minSpeed.setText("Min-Speed:");
            this.minSpeed.setSelected(true);
            this.spdLengthGroup.add(this.minSpeed);
            this.minSpeed.addActionListener(this);
          }
          {
            this.minSpeedSlide = new JSlider();
            this.speedLen.add(this.minSpeedSlide);
            this.minSpeedSlide.setMajorTickSpacing(25);
            this.minSpeedSlide.setPaintTicks(true);
            this.minSpeedSlide.setPaintLabels(true);
            this.minSpeedSlide.addChangeListener(this);
          }
          {
            this.maxSpeed = new JRadioButton();
            this.speedLen.add(this.maxSpeed);
            this.maxSpeed.setText("Max-Speed");
            this.spdLengthGroup.add(this.maxSpeed);
            this.maxSpeed.addActionListener(this);
          }
          {
            this.maxSpeedSlide = new JSlider();
            this.speedLen.add(this.maxSpeedSlide);
            this.maxSpeedSlide.setMajorTickSpacing(25);
            this.maxSpeedSlide.setPaintTicks(true);
            this.maxSpeedSlide.setPaintLabels(true);
            this.maxSpeedSlide.setEnabled(false);
            this.maxSpeedSlide.addChangeListener(this);
          }
        }
        {
          this.other = new JPanel();
          GridLayout otherLayout = new GridLayout(7, 1);
          otherLayout.setRows(7);
          this.other.setLayout(otherLayout);
          // FlowLayout otherLayout = new FlowLayout();
          // otherLayout.setAlignment(FlowLayout.LEFT);
          // other.setLayout(otherLayout);
          this.EditTabPane.addTab("Other", null, this.other, null);
          {
            this.active = new JCheckBox();
            this.other.add(this.active);
            this.active.setText("Active Player");
            this.active.addActionListener(this);
          }
          {
            this.roundView = new JCheckBox();
            this.other.add(this.roundView);
            this.roundView.setText("Round-View");
            this.roundView.addActionListener(this);
          }
        }
      }
      this.setSize(420, 300);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * This method handles all actions available for for this dialog, i.e. all
   * buttons, checkboxes and slides are handled in here!
   */
  public void actionPerformed(ActionEvent arg0) {

    if (arg0.getSource() == this.fixedPosition) {
      this.otm.setType(POSITION_TYPE.FIXED);
      this.lengthSlide.setEnabled(false);
      this.heightSlide.setEnabled(false);
    }
    else if (arg0.getSource() == this.rectPosition) {
      this.otm.setType(POSITION_TYPE.RECTANGULAR);
      this.lengthSlide.setEnabled(true);
      this.heightSlide.setEnabled(true);
    }
    else if (arg0.getSource() == this.circPosition) {
      this.otm.setType(POSITION_TYPE.CIRCULAR);
      this.lengthSlide.setEnabled(true);
      this.heightSlide.setEnabled(true);
    }
    else if (arg0.getSource() == this.minSpeed) {
      this.minSpeedSlide.setEnabled(true);
      this.maxSpeedSlide.setEnabled(false);
    }
    else if (arg0.getSource() == this.maxSpeed) {
      this.minSpeedSlide.setEnabled(false);
      this.maxSpeedSlide.setEnabled(true);
    }
    else if (arg0.getSource() == this.alignWithBody) {
      if (this.object instanceof Player) {
        PlayerTrainingModel ptm = (PlayerTrainingModel) this.otm;
        ptm.setAlignSpeedWithBody(this.alignWithBody.isSelected());
      }
    }
    else if (arg0.getSource() == this.active) {
      if (this.object instanceof Player) {
        PlayerTrainingModel ptm = (PlayerTrainingModel) this.otm;
        ptm.setActive(this.active.isSelected());
      }
    }
    else if (arg0.getSource() == this.roundView) {
      if (this.object instanceof Player) {
        PlayerTrainingModel ptm = (PlayerTrainingModel) this.otm;
        ptm.setRoundView(this.roundView.isSelected());
      }
    }
  }

  /**
   * MouseListener is only for the PlayerButton. Received MouseEvents are
   * forwarded to these method to modify the TrainingModel in a intuitive
   * manner! The Event depends on the active tab!
   * 
   * @param evt -
   *          the mouse-event
   */
  public void mouseClicked(MouseEvent evt) {

    // if the position-panel is active/visible
    if (this.EditTabPane.getSelectedComponent() == this.position) {
      Dimension dim = this.objectTrainingButton.getSize();
      int cy = dim.width / 2;
      int cx = dim.height / 2;
      Vektor veTo = new Vektor(Vektor.XY, evt.getPoint().x - cy,
          evt.getPoint().y - cx);
      veTo.multThis(this.mapFactor);

      this.object.pos.x += veTo.x;
      this.object.pos.y += veTo.y;
      this.otm.setPosition(this.object.pos);
      this.objectTrainingButton.repaint();
    }
    if (this.EditTabPane.getSelectedComponent() == this.angle) {
      if (this.object instanceof Player) {
        Player player = (Player) this.object;
        PlayerTrainingModel ptm = (PlayerTrainingModel) this.otm;

        Dimension dim = this.objectTrainingButton.getSize();
        int cx = dim.width / 2;
        int cy = dim.height / 2;
        Vektor veTo = new Vektor(Vektor.XY, evt.getPoint().y - cy, evt
            .getPoint().x - cx);
        float angle = (float) veTo.getAngle();
        player.angle = angle;
        ptm.setBody_angle(angle);
        this.objectTrainingButton.repaint();
      }
    }
    if (this.EditTabPane.getSelectedComponent() == this.speedDir) {
      Dimension dim = this.objectTrainingButton.getSize();
      int cx = dim.width / 2;
      int cy = dim.height / 2;
      Vektor veTo = new Vektor(Vektor.XY, evt.getPoint().y - cy,
          evt.getPoint().x - cx);
      float angle = (float) veTo.getAngle();
      this.otm.setSpeed_angle(angle);
    }
  }

  public void mousePressed(MouseEvent evt) {

  }

  public void mouseReleased(MouseEvent evt) {

  }

  /**
   * This method sets a point to the field, which is equivalent to the
   * mouse-position on the trainings- button. This might help to keep
   * orientation when the buttons positioning or turning abilities are used.
   */
  public void mouseEntered(MouseEvent evt) {

    Dimension dim = this.objectTrainingButton.getSize();
    int cy = dim.width / 2;
    int cx = dim.height / 2;
    Vektor veTo = new Vektor(Vektor.XY, evt.getPoint().x - cy,
        evt.getPoint().y - cx);
    veTo.multThis(this.mapFactor);

    Point2f observer = new Point2f();
    observer.x = (float) (this.object.pos.x + veTo.x);
    observer.y = (float) (this.object.pos.y + veTo.y);

    this.otm.setObservePoint(observer);
  }

  /**
   * This method removes a point to the field, which is equivalent to the
   * mouse-position on the trainings- button.
   */
  public void mouseExited(MouseEvent evt) {

    this.otm.setObservePoint(null);
  }

  public void mouseDragged(MouseEvent evt) {

  }

  /**
   * This method updates the observer-button
   */
  public void mouseMoved(MouseEvent evt) {

    Dimension dim = this.objectTrainingButton.getSize();
    int cy = dim.width / 2;
    int cx = dim.height / 2;
    Vektor veTo = new Vektor(Vektor.XY, evt.getPoint().x - cy,
        evt.getPoint().y - cx);
    veTo.multThis(this.mapFactor);

    Point2f observer = new Point2f();
    observer.x = (float) (this.object.pos.x + veTo.x);
    observer.y = (float) (this.object.pos.y + veTo.y);

    this.otm.setObservePoint(observer);
  }

  /**
   * This method checks all changes in the slides of the dialog, e.g. for
   * changes in the positioning.
   * 
   * @param arg0 -
   *          the event cause by the action
   */
  public void stateChanged(ChangeEvent arg0) {

    if (arg0.getSource() == this.lengthSlide) {
      int value = this.lengthSlide.getValue();
      this.otm.setY_pos_diff(value * this.posFactor);
    }
    else if (arg0.getSource() == this.heightSlide) {
      int value = this.heightSlide.getValue();
      this.otm.setX_pos_diff(value * this.posFactor);
    }
    else if (arg0.getSource() == this.diffSlide) {
      if (this.object instanceof Player) {
        PlayerTrainingModel ptm = (PlayerTrainingModel) this.otm;
        int value = this.diffSlide.getValue();
        ptm.setBody_angle_diff(value);
      }
    }
    else if (arg0.getSource() == this.sdirDiffSlide) {
      int value = this.sdirDiffSlide.getValue();
      this.otm.setSpeed_angle_diff(value);
    }
    else if (arg0.getSource() == this.minSpeedSlide) {
      int value = this.minSpeedSlide.getValue();
      this.otm.setMin_speed(value);
      this.maxSpeedSlide.setValue(this.otm.getMax_speed());
    }
    else if (arg0.getSource() == this.maxSpeedSlide) {
      int value = this.maxSpeedSlide.getValue();
      this.otm.setMax_speed(value);
      this.minSpeedSlide.setValue(this.otm.getMin_speed());
    }
  }

  /**
   * This method is used to turn the body/speed-dirs angle in small steps -
   * moving the wheel up will increase the angle, moving down decreases.
   * 
   * @param evt -
   *          the mouse-wheel event
   */
  public void mouseWheelMoved(MouseWheelEvent evt) {

    // change the body angle
    if (this.EditTabPane.getSelectedComponent() == this.angle) {
      if (this.object instanceof Player) {
        Player player = (Player) this.object;
        PlayerTrainingModel ptm = (PlayerTrainingModel) this.otm;
        if (evt.getWheelRotation() < 0) {
          player.angle += 2;
          ptm.setBody_angle(player.angle);
        }
        else {
          player.angle -= 2;
          ptm.setBody_angle(player.angle);
        }
        this.objectTrainingButton.repaint();
      }
    }
    else if (this.EditTabPane.getSelectedComponent() == this.speedDir) {
      if (evt.getWheelRotation() < 0) {
        this.otm.setSpeed_angle(this.otm.getSpeed_angle() + 2);
      }
      else {
        this.otm.setSpeed_angle(this.otm.getSpeed_angle() - 2);
      }
    }
  }

}
